package com.sinvo.oa.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sinvo.oa.entity.vo.system.MetaVo;
import com.sinvo.oa.entity.vo.system.RouterVo;
import com.sinvo.oa.mapper.SysMenuMapper;
import com.sinvo.oa.mapper.SysRoleMenuMapper;
import com.sinvo.oa.service.SysMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sinvo.oa.util.MenuUtils;
import com.sinvo.oa.exception.CustomException;
import com.sinvo.oa.result.ResultCode;
import com.sinvo.oa.entity.model.system.SysMenu;
import com.sinvo.oa.entity.model.system.SysRoleMenu;
import com.sinvo.oa.entity.vo.system.AssignMenuVo;
import com.sinvo.oa.util.TreeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description SysMenuService实现类
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    @Autowired
    private SysMenuMapper sysMenuMapper;

    @Autowired
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Override
    public List<SysMenu> getAllMenuNodes() {
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(SysMenu::getSortValue);
        //获取所有菜单
        List<SysMenu> menuList = this.list(queryWrapper);
        //调用工具类进行树化
        List<SysMenu> menuTreeList = TreeUtils.listToTree(menuList,"parentId","id");
        return menuTreeList;
    }

    @Override
    public void updateMenu(SysMenu sysMenu) {
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getName,sysMenu.getName());
        SysMenu one = this.getOne(queryWrapper);
        if (one != null && one.getId() != sysMenu.getId()) {
            throw new CustomException(ResultCode.DATA_ERROR.getCode(), "菜单名重复");
        }
        boolean success = this.updateById(sysMenu);
        if (!success) {
            throw new CustomException(ResultCode.SERVICE_ERROR.getCode(), "更新失败，请重试");
        }
    }

    @Override
    public void saveMenu(SysMenu sysMenu) {
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getName,sysMenu.getName());
        int count = this.count(queryWrapper);
        if (count > 0) {
            throw new CustomException(ResultCode.DATA_ERROR.getCode(), "菜单名重复");
        }
        boolean success = this.save(sysMenu);
        if (!success) {
            throw new CustomException(ResultCode.SERVICE_ERROR.getCode(), "新增失败，请重试");
        }
    }

    @Transactional
    @Override
    public void removeMenuById(Long id) {
        //判断当前菜单是否有子菜单
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getParentId, id);
        int count = this.count(queryWrapper);
        //当前menuId为parentId 存在子菜单
        if (count > 0) {
            throw new CustomException(ResultCode.SERVICE_ERROR.getCode(), "存在子菜单，不能删除");
        }
        //删除菜单
        this.removeById(id);
        //同时删除关系表中的数据
        LambdaQueryWrapper<SysRoleMenu> roleMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roleMenuLambdaQueryWrapper.eq(SysRoleMenu::getMenuId, id);
        sysRoleMenuMapper.delete(roleMenuLambdaQueryWrapper);
    }

    @Override
    public List<SysMenu> getMenuByRoleId(Long roleId) {
        //查询所有菜单 status=1
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getStatus, 1);
        List<SysMenu> allMenuList = this.list(queryWrapper);
        //查询roleId下的menuId
        List<Long> menuIdList = sysMenuMapper.queryMenuByRoleId(roleId);

        allMenuList.stream().forEach(item -> {
            if (menuIdList.contains(item.getId())) {
                item.setSelect(true);
            } else {
                item.setSelect(false);
            }
        });
        //进行树化
        List<SysMenu> treeifiedList = TreeUtils.listToTree(allMenuList,"parentId","id");
//        List<SysMenu> treeifiedList = MenuUtils.treeify(allMenuList);
        return treeifiedList;
    }

    @Transactional
    @Override
    public boolean doAssign(AssignMenuVo assignMenuVo) {
        //根据roleId删除原有的菜单
        LambdaQueryWrapper<SysRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysRoleMenu::getRoleId, assignMenuVo.getRoleId());
        sysRoleMenuMapper.delete(queryWrapper);
        //stream将参数中的menuIdList转为roleMenuList
        List<SysRoleMenu> roleMenuList = assignMenuVo.getMenuIdList().stream().map((id) -> {
            SysRoleMenu sysRoleMenu = new SysRoleMenu();
            sysRoleMenu.setRoleId(assignMenuVo.getRoleId());
            sysRoleMenu.setMenuId(id);
            return sysRoleMenu;
        }).collect(Collectors.toList());
        //进行批量添加
        sysRoleMenuMapper.saveRoleMenuByBatch(roleMenuList);
        return true;
    }

    @Override
    public boolean changeStatus(Long id, Integer status) {
        //根据id获取菜单
        SysMenu menu = this.getById(id);
        //修改状态
        menu.setStatus(status);
        //更新
        this.updateById(menu);
        return true;
    }

    @Override
    public List<RouterVo> findUserMenuListByUserId(Long userId) {
        //userId->roleId->menuId 3表联查
        List<SysMenu> menuList = sysMenuMapper.queryMenuListByUserId(userId);
        //构建成与前端一致的结构
        //首先进行树化
        List<SysMenu> treeifiedList = TreeUtils.listToTree(menuList,"parentId","id");
        //构建路由
        List<RouterVo> routerList = buildRouter(treeifiedList);
        System.out.println("路由："+routerList);
        return routerList;
    }

    /**
     * 内部方法 构建路由
     * @param menus menuList
     * @return routerList
     */
    private List<RouterVo> buildRouter(List<SysMenu> menus) {
        //返回结果
        List<RouterVo> routers = new ArrayList<>();
        //遍历menus
        for (SysMenu menu : menus) {
            RouterVo router = new RouterVo();
            //补全数据字段
            router.setHidden(false);
            router.setAlwaysShow(false);
            router.setPath(getRouterPath(menu));
            router.setComponent(menu.getComponent());
            router.setMeta(new MetaVo(menu.getName(), menu.getIcon()));
            //封装下一层数据
            List<SysMenu> children = menu.getChildren();
            if (menu.getType() == 1) {
                //菜单的子目录应该是按钮 而component不为空 说明 是隐藏隐藏路由
                //加载隐藏路由
                List<SysMenu> hiddenMenuList = children.stream()
                        .filter(item -> !StringUtils.isEmpty(item.getComponent()))
                        .collect(Collectors.toList());
                //遍历隐藏路由
                for (SysMenu hiddenMenu : hiddenMenuList) {
                    RouterVo hiddenRouter = new RouterVo();
                    //补全数据字段
                    hiddenRouter.setHidden(true);
                    hiddenRouter.setAlwaysShow(false);
                    hiddenRouter.setPath(getRouterPath(hiddenMenu));
                    hiddenRouter.setComponent(hiddenMenu.getComponent());
                    hiddenRouter.setMeta(new MetaVo(hiddenMenu.getName(), hiddenMenu.getIcon()));
                    //添加
                    routers.add(hiddenRouter);
                }
            } else {
                if (!CollectionUtils.isEmpty(children) && children.size() > 0) {
                    router.setAlwaysShow(true);
                    router.setChildren(buildRouter(children));
                }
            }
            routers.add(router);
        }
        return routers;
    }

    /**
     * 内部方法 获取menu的路径 如/system | sysRole
     * @param menu getPath()
     * @return String
     */
    private String getRouterPath(SysMenu menu) {
        String routerPath = null;
        //如果是父节点 开头添加/
        if (menu.getParentId() == 0) {
            routerPath = "/" + menu.getPath();
        } else {
            //不是则不添加
            routerPath = menu.getPath();
        }
        return routerPath;
    }

    @Override
    public List<String> findUserPermsByUserId(Long userId) {
        List<SysMenu> menuList = sysMenuMapper.queryMenuListByUserId(userId);
        //过滤出type=2即 按钮的菜单 获取其权限标识字段 返回
        List<String> permsList = menuList.stream()
                .filter(item -> item.getType() == 2)
                .map(item -> item.getPerms())
                .collect(Collectors.toList());

        return permsList;
    }
}
